package com.tian.service;

import com.alibaba.fastjson.JSON;
import com.tian.client.ExchangeCodeClient;
import com.tian.client.UserCouponClient;
import com.tian.common.CommonResult;
import com.tian.config.WXPayConfig;
import com.tian.constant.RabbitMQConstant;
import com.tian.dto.ChargePayReqDto;
import com.tian.dto.coupon.CheckCouponReqDto;
import com.tian.dto.coupon.CheckCouponRespDto;
import com.tian.dto.coupon.CouponCacheDto;
import com.tian.dto.coupon.UserCouponCacheDto;
import com.tian.dto.exchange.CheckExchangeCodeReqDto;
import com.tian.dto.exchange.CheckExchangeCodeRespDto;
import com.tian.dto.exchange.ExchangeCodeDto;
import com.tian.entity.ChargePayOrder;
import com.tian.entity.OrderUseCoupon;
import com.tian.enums.*;
import com.tian.exception.BusinessException;
import com.tian.mapper.ChargePayOrderMapper;
import com.tian.mapper.OrderUseCouponMapper;
import com.tian.message.*;
import com.tian.producer.MqProducer;
import com.tian.strategy.CalculateDiscountAmountService;
import com.tian.strategy.CalculateDiscountAmountStrategy;
import com.tian.util.ChargeMarketRedisKeyPrefix;
import com.tian.util.PayRedisPrefixUtil;
import com.tian.util.RedisConstantPre;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * {@code @description:} TODO
 *
 * @author tianwc 公众号：Java后端技术全栈
 * 在线刷题 1200+java面试题和1000+篇技术文章：<a href="https://woaijava.cc/">博客地址</a>
 * {@code @date:} 2025-01-20 10:54
 * {@code @version:} 1.0
 */
@Slf4j
@Component
public class PayBaseService {

    @Resource
    private WXPayConfig wxPayConfig;
    @Resource
    private ChargePayOrderMapper chargePayOrderMapper;
    @Resource
    private RedissonClient redissonClient;
    @Resource
    private MqProducer mqProducer;
    @Resource
    private OrderUseCouponMapper orderUseCouponMapper;
    @Resource
    private ExchangeCodeClient exchangeCodeClient;
    @Resource
    private UserCouponClient userCouponClient;

    @PostConstruct // 注解确保在应用启动时执行此方法
    public void initLog() {
        log.info("PayBaseService init success");
    }

    public String test() {
        RBucket<String> bucket = redissonClient.getBucket("test111111");
        bucket.set("test111111");
        return bucket.get();
    }

    public String checkCoupons(ChargePayReqDto chargePayReqDto) {
        List<Long> userCouponIdList = chargePayReqDto.getUserCouponIdList();
        BigDecimal orderAmount = chargePayReqDto.getAmount();
        CheckCouponReqDto checkCouponReqDto = new CheckCouponReqDto();
        checkCouponReqDto.setUserCouponIdList(userCouponIdList);
        checkCouponReqDto.setOrderAmount(orderAmount);
        CommonResult<CheckCouponRespDto> checkCouponRespDtoCommonResult = userCouponClient.checkCoupon(checkCouponReqDto);
        StringBuilder message = new StringBuilder();
        if (checkCouponRespDtoCommonResult.getCode() == ResultCode.SUCCESS.getCode()) {
            CheckCouponRespDto data = checkCouponRespDtoCommonResult.getData();
            Map<Long, String> couponCheckResultMap = data.getCouponCheckResultMap();
            if (CollectionUtils.isEmpty(couponCheckResultMap)) {
                return null;
            }
            for (Map.Entry<Long, String> entry : couponCheckResultMap.entrySet()) {
                message.append(entry.getValue()).append(";");
            }
        }
        return message.toString();
    }
    public void paySuccess(String orderNo) {
        // 更新支付订单状态PAID
        ChargePayOrder chargePayOrder = chargePayOrderMapper.selectByPrimaryOrder(orderNo);
        if (chargePayOrder != null) {
            chargePayOrder.setPayStatus(PayStatusEnum.PAID.getCode());
            // 没有关联充电记录，则更新用户余额
            if (chargePayOrder.getChargeRecordId() == null || chargePayOrder.getChargeRecordId() == 0) {
                UserBalanceIncrMessage userBalanceIncrMessage = new UserBalanceIncrMessage();
                userBalanceIncrMessage.setUserId(chargePayOrder.getUserId());
                userBalanceIncrMessage.setChangeBalance(chargePayOrder.getAmount().add(chargePayOrder.getDiscountAmount()));
                userBalanceIncrMessage.setReqId(chargePayOrder.getOrderNo());
                userBalanceIncrMessage.setChangeType(UserBalanceChangeTypeEnum.USER_RECHARGE.getType());
                mqProducer.sendMessage(JSON.toJSONString(userBalanceIncrMessage), RabbitMQConstant.USER_BALANCE_INCREASE_EXCHANGE, RabbitMQConstant.USER_BALANCE_INCREASE_ROUTING_KEY, PayRetryMessageTypeEnum.USER_BALANCE_INCREASED.getType());
            }
            UserCouponMessage userCouponMessage = new UserCouponMessage();
            userCouponMessage.setUserId(chargePayOrder.getUserId());
            userCouponMessage.setOrderId(chargePayOrder.getId());
            userCouponMessage.setStatus(UserCouponStatusEnum.USED.getStatus());
            //修改订单状态和用户优惠券状态
            updateOrderStatus(chargePayOrder, userCouponMessage, RabbitMQConstant.USER_USE_COUPON_EXCHANGE, RabbitMQConstant.USER_USE_COUPON_ROUTING_KEY, PayRetryMessageTypeEnum.USER_USED_COUPON.getType());
            if (chargePayOrder.getChargeRecordId() != null) {
                //修改充电记录状态为充电完成（支付完成）
                sendChargingOrderStatus(chargePayOrder.getChargeRecordId(), ChargingStatusEnum.PAY_FINISHED.getStatus());
            }
            CouponUsedStatisticsMessage couponUsedStatisticsMessage = new CouponUsedStatisticsMessage();
            couponUsedStatisticsMessage.setOrderId(chargePayOrder.getId());
            couponUsedStatisticsMessage.setOrderAmount(chargePayOrder.getAmount());
            //用户优惠券使用统计
            mqProducer.sendMessage(JSON.toJSONString(couponUsedStatisticsMessage), RabbitMQConstant.COUPON_USE_STATISTICS_EXCHANGE, RabbitMQConstant.COUPON_USE_STATISTICS_ROUTING_KEY, PayRetryMessageTypeEnum.COUPON_USE_STATISTICS.getType());
            //兑换码使用状态为已使用
            sendMsg4UpdateExchangeCodeStatus(chargePayOrder.getId(), chargePayOrder.getUserId(), ExchangeCodeStatusEnum.USED.getCode());
        }
    }

    public void payFailed(String orderNo, PayStatusEnum failed) {
        ChargePayOrder chargePayOrder = chargePayOrderMapper.selectByPrimaryOrder(orderNo);
        if (chargePayOrder != null) {
            chargePayOrder.setPayStatus(failed.getCode());
            UserCouponMessage userCouponMessage = new UserCouponMessage();
            userCouponMessage.setUserId(chargePayOrder.getUserId());
            userCouponMessage.setOrderId(chargePayOrder.getId());
            userCouponMessage.setStatus(UserCouponStatusEnum.INIT.getStatus());
            //修改订单状态和用户优惠券状态
            updateOrderStatus(chargePayOrder, userCouponMessage, RabbitMQConstant.FREE_USER_USE_COUPON_EXCHANGE, RabbitMQConstant.FREE_USER_USE_COUPON_ROUTING_KEY, PayRetryMessageTypeEnum.FREE_USER_USED_COUPON.getType());
            if (chargePayOrder.getChargeRecordId() != null) {
                //修改充电记录状态为充电完成（待支付）
                sendChargingOrderStatus(chargePayOrder.getChargeRecordId(), ChargingStatusEnum.CHARGED.getStatus());
            }
            //兑换码使用状态为未使用
            sendMsg4UpdateExchangeCodeStatus(chargePayOrder.getId(), chargePayOrder.getUserId(), ExchangeCodeStatusEnum.NOT_USED.getCode());
        }
    }

    /**
     * 兑换码使用状态更新(发送消息到MQ中)
     */
    public void sendMsg4UpdateExchangeCodeStatus(Long orderId, Long userId, int status) {
        RBucket<String> bucket = redissonClient.getBucket(RedisConstantPre.EXCHANGE_CODE_USING_KEY  + orderId);
        if (bucket.get() != null) {
            UserUseCouponExchangeCodeMessage userUseCouponExchangeCodeMessage = new UserUseCouponExchangeCodeMessage();
            userUseCouponExchangeCodeMessage.setUserId(userId);
            userUseCouponExchangeCodeMessage.setOrderId(orderId);
            userUseCouponExchangeCodeMessage.setStatus(status);
            userUseCouponExchangeCodeMessage.setExchangeCode(bucket.get());
            log.info("发送兑换码使用状态变更消息：{}", JSON.toJSONString(userUseCouponExchangeCodeMessage));
            mqProducer.sendMessage(JSON.toJSONString(userUseCouponExchangeCodeMessage), RabbitMQConstant.USER_USE_COUPON_EXCHANGE_CODE_EXCHANGE, RabbitMQConstant.USER_USE_COUPON_EXCHANGE_CODE_ROUTING_KEY,
                    PayRetryMessageTypeEnum.COUPON_EXCHANGE_CODE_USED.getType());
        }
    }

    /**
     * 充电订单状态变更
     *
     * @param chargeRecordId 充电记录id
     * @param status         充电记录状态
     */
    public void sendChargingOrderStatus(Long chargeRecordId, int status) {
        ChargingOrderMessage chargingOrderMessage = new ChargingOrderMessage();
        chargingOrderMessage.setOrderId(chargeRecordId);
        chargingOrderMessage.setStatus(status);
        mqProducer.sendMessage(JSON.toJSONString(chargingOrderMessage), RabbitMQConstant.CHARGING_ORDER_STATUS_CHANGE_EXCHANGE, RabbitMQConstant.CHARGING_ORDER_STATUS_CHANGE_ROUTING_KEY,
                PayRetryMessageTypeEnum.CHARGE_ORDER_STATUS_UPDATE.getType());
    }


    /**
     * 修改订单状态和用户优惠券状态
     */
    public void updateOrderStatus(ChargePayOrder chargePayOrder,
                                   UserCouponMessage userCouponMessage,
                                   String mqExchange, String mqRoutingKey, int retryMessageType) {
        chargePayOrderMapper.updateByPrimaryKey(chargePayOrder);
        orderUseCouponMapper.updateByOrderId(chargePayOrder.getId(), chargePayOrder.getPayStatus());
        int count = orderUseCouponMapper.countByOrderId(chargePayOrder.getId());
        //如果有使用到优惠券，则修改用户优惠券状态
        if (count > 0) {
            mqProducer.sendMessage(JSON.toJSONString(userCouponMessage), mqExchange, mqRoutingKey, retryMessageType);
        }
    }

    public CheckExchangeCodeRespDto checkExchangeCode(ChargePayReqDto chargePayReqDto) {
        RBucket<String> bucket = redissonClient.getBucket(RedisConstantPre.EXCHANGE_CODE_KEY + chargePayReqDto.getExchangeCode());
        ExchangeCodeDto exchangeCodeDto = JSON.parseObject(bucket.get(), ExchangeCodeDto.class);
        if (exchangeCodeDto == null) {
            throw new BusinessException("兑换码不存在");
        }
        CheckExchangeCodeReqDto checkExchangeCodeReqDto = new CheckExchangeCodeReqDto();
        checkExchangeCodeReqDto.setCode(chargePayReqDto.getExchangeCode());
        checkExchangeCodeReqDto.setAmount(chargePayReqDto.getAmount());
        CommonResult<CheckExchangeCodeRespDto> codeCheckResult = exchangeCodeClient.validateCode(checkExchangeCodeReqDto);
        if (ResultCode.SUCCESS.getCode() != codeCheckResult.getCode()) {
            throw new BusinessException(codeCheckResult.getMessage());
        }
        return codeCheckResult.getData();
    }

    /**
     * 支付服务保存订单优惠券关联表
     * 也可以采用MQ模式，异步保存订单优惠券关联表
     */
    public void insertOrderCoupon(List<Long> userCouponIdList, ChargePayOrder chargePayOrder, Map<Long, BigDecimal> couponAmountMap) {
        List<OrderUseCoupon> orderUseCouponList = new ArrayList<>();
        userCouponIdList.forEach(userCouponId -> {
            OrderUseCoupon orderUseCoupon = new OrderUseCoupon();
            orderUseCoupon.setOrderId(chargePayOrder.getId());
            orderUseCoupon.setUserCouponId(userCouponId);
            orderUseCoupon.setStatus(PayStatusEnum.PAYING.getCode());
            orderUseCoupon.setCouponAmount(couponAmountMap.get(userCouponId));
            orderUseCouponList.add(orderUseCoupon);
        });
        orderUseCouponMapper.insertBatch(orderUseCouponList);
    }

    /**
     * 发送消息到MQ，更新用户兑换码状态为使用中
     */
    public void sendMsgUpdateExchangeCodeStatus(String code, Long userId, Long orderId, int status) {
        UserUseCouponExchangeCodeMessage userUseCouponExchangeCodeMessage = new UserUseCouponExchangeCodeMessage();
        userUseCouponExchangeCodeMessage.setUserId(userId);
        userUseCouponExchangeCodeMessage.setExchangeCode(code);
        userUseCouponExchangeCodeMessage.setOrderId(orderId);
        userUseCouponExchangeCodeMessage.setStatus(status);
        mqProducer.sendMessage(JSON.toJSONString(userUseCouponExchangeCodeMessage), RabbitMQConstant.USER_USE_COUPON_EXCHANGE, RabbitMQConstant.USER_USE_COUPON_ROUTING_KEY, PayRetryMessageTypeEnum.USER_USING_COUPON.getType());
        redissonClient.getBucket(PayRedisPrefixUtil.ORDER_CODE_PREFIX + orderId).set(code);
    }

    public void sendMsgUpdateUserCouponStatus(List<Long> userCouponIdList, ChargePayOrder chargePayOrder) {
        UserCouponMessage userCouponMessage = new UserCouponMessage();
        userCouponMessage.setUserCouponIdList(userCouponIdList);
        userCouponMessage.setOrderId(chargePayOrder.getId());
        userCouponMessage.setStatus(UserCouponStatusEnum.PRE_USE.getStatus());
        String msg = JSON.toJSONString(userCouponMessage);
        log.info("发送用户优惠券状态变更消息：{}", msg);
        mqProducer.sendMessage(msg, RabbitMQConstant.USER_USE_COUPON_EXCHANGE, RabbitMQConstant.USER_USE_COUPON_ROUTING_KEY, PayRetryMessageTypeEnum.USER_USING_COUPON.getType());
    }

    public BigDecimal calculateCouponAmount(Map<Long, BigDecimal> couponAmountMap, BigDecimal orderAmount, List<Long> userCouponIdList) {
        BigDecimal amount = orderAmount;
        for (Long userCouponId : userCouponIdList) {
            //获取用户优惠券记录信息
            RBucket<String> userCouponBucket = redissonClient.getBucket(ChargeMarketRedisKeyPrefix.CHARGE_USER_COUPON_KEY + userCouponId);
            UserCouponCacheDto userCouponCacheDto = JSON.parseObject(userCouponBucket.get(), UserCouponCacheDto.class);
            //获取优惠券信息
            RBucket<String> couponBucket = redissonClient.getBucket(ChargeMarketRedisKeyPrefix.CHARGE_COUPON_KEY + userCouponCacheDto.getCouponId());
            CouponCacheDto couponCacheDto = JSON.parseObject(couponBucket.get(), CouponCacheDto.class);
            //优惠券面值
            BigDecimal couponFaceAmount = couponCacheDto.getFaceValue();
            //优惠券类型 1:满减券 2:折扣券 3:无门槛券（直接抵扣）
            Integer type = couponCacheDto.getUseType();

            if (type == CouponUseTypeEnum.FULL_REDUCE.getType()) {
                //判断是否满足满减条件
                //比如设置的是满100元减10，那这个amount就必须大于等于100元才减去10元
                if (amount.compareTo(couponCacheDto.getFullReduce()) < 0) {
                    throw new BusinessException("优惠券不满足满减条件");
                }
            }
            //计算优惠券金额
            CalculateDiscountAmountService discountAmountService = CalculateDiscountAmountStrategy.getCalculateDiscountAmountService(type);
            amount = discountAmountService.calculateDiscountAmount(amount, couponFaceAmount);
            couponAmountMap.put(userCouponId, couponFaceAmount);
            //折扣券，则折扣金额需要进行百分比计算
            if (type == CouponUseTypeEnum.DISCOUNT.getType()) {
                couponAmountMap.put(userCouponId, orderAmount.subtract(amount));
            }
        }
        return amount;
    }
}
